#ifndef SIMULATION_H
#define SIMULATION_H

#include <set>

#include <btBulletDynamicsCommon.h>

#include "individual.h"

//The SimulationWorld class describes the world where we can makes Individual progress
// A SimulationWorld can control the simulation progress over time (this simulation time can be bounded)
// The 3D world is also bounded by width, height and depth
// Several sensors are available to listen to the simulation progress
class SimulationWorld
{
    //definition
public:
    typedef std::set<Individual *, IndividualIdOrdering> IndividualCollection;

    //ctors
public:
    PHYSICS_ENGINE_API explicit SimulationWorld(
            btScalar maximum_duration = 10 * 60 * 60, //10min
            btScalar width = 200.,   btScalar height = 200.,    btScalar depth = 200.,
            btScalar gravity_x = 0., btScalar gravity_y = -9.8, btScalar gravity_z = 0.);
    PHYSICS_ENGINE_API ~SimulationWorld(void);

public:
    //This function run the simulation for the given 'time_delta' time (in seconds)
    //  internally, this function call the bullet library 'virtual int btDynamicsWorld::stepSimulation(btScalar timeStep, int maxSubSteps, btScalar fixedTimeStep)'
    PHYSICS_ENGINE_API bool updateWorld(btScalar time_delta);

    PHYSICS_ENGINE_API bool add    (Individual * individual);
    PHYSICS_ENGINE_API bool remove (Individual * individual);

    //Really necessary ?
    PHYSICS_ENGINE_API IndividualCollection population() const;

    //simulation parameters
private:
    const btScalar  m_maximum_simulation_duration;
    const btVector3 m_world_dimension;
    const btVector3 m_world_gravity;

    //bullet library physics
private:
    btDynamicsWorld*     m_world;
    IndividualCollection m_population;

    //world state
private:
    btScalar            m_simulation_time;

    //disallow copy and assign
private:
    SimulationWorld(const SimulationWorld& that);
    SimulationWorld& operator =(const SimulationWorld& that);
};

#endif // SIMULATION_H
